package com.house.framework.utils;

import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.house.utils.StringUtils;
import lombok.SneakyThrows;

import java.io.Serializable;
import java.lang.invoke.SerializedLambda;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Objects;
import java.util.function.Function;

public class FieldUtil {
    @FunctionalInterface
    public static interface SFunction<T, R> extends Function<T, R>, Serializable {
    }

    @SneakyThrows
    public  static <T> String getFieldName(SFunction<T, ?> fn){
        // 从function取出序列化方法
        Method writeReplaceMethod;
        try {
            writeReplaceMethod = fn.getClass().getDeclaredMethod("writeReplace");
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        }
        // 从序列化方法取出序列化的lambda信息
        writeReplaceMethod.setAccessible(true);
        SerializedLambda serializedLambda;
        try {
            serializedLambda = (SerializedLambda) writeReplaceMethod.invoke(fn);
        } catch (IllegalAccessException | InvocationTargetException e) {
            throw new RuntimeException(e);
        }
        // 从lambda信息取出method、field、class等
        String fieldName = serializedLambda.getImplMethodName().substring("get".length());
        fieldName = fieldName.replaceFirst(fieldName.charAt(0) + StringUtils.EMPTY, (fieldName.charAt(0) + StringUtils.EMPTY).toLowerCase());
        Field field;
        try {
            Class<?> cls = Class.forName(serializedLambda.getImplClass().replace("/", "."));

            field = cls.getDeclaredField(fieldName);
            TableField tableField = field.getAnnotation(TableField.class);
            if(Objects.nonNull(tableField)){
                return  tableField.value();
            }
            TableId tableId = field.getAnnotation(TableId.class);
            if(Objects.nonNull(tableId)){
                return  tableId.value();
            }
            return  field.getName();
        } catch (ClassNotFoundException | NoSuchFieldException e) {
            throw new RuntimeException(e);
        }
    }
}
